package org.jeecg.modules.monitoring.j_monitoring.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.CommonUtils;
import org.jeecg.modules.monitoring.j_monitoring.constantConfig.MonitorConstant;
import org.jeecg.modules.monitoring.j_monitoring.entity.*;
import org.jeecg.modules.monitoring.j_monitoring.gatewayData.Virtual;
import org.jeecg.modules.monitoring.j_monitoring.mapper.*;
import org.jeecg.modules.monitoring.j_monitoring.service.IMGlComputingResourceService;
import org.jeecg.modules.monitoring.j_monitoring.service.IMGlNetworkResourceService;
import org.jeecg.modules.monitoring.j_monitoring.service.IMGlStorageResourcesService;
import org.jeecg.modules.monitoring.j_monitoring.service.IMGlVirtualizationClusterService;
import org.jeecgframework.core.util.ApplicationContextUtil;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * @Description: 虚拟化群集
 * @Author: xiaoyq
 * @Date: 2023-02-23
 * @Version: V1.0
 */
@Service
public class MGlVirtualizationClusterServiceImpl extends ServiceImpl<MGlVirtualizationClusterMapper, MGlVirtualizationCluster> implements IMGlVirtualizationClusterService {

    @Resource
    private MGlComputingResourceMapper computingResourceMapper;

    @Resource
    private MGlVirtualMachineMapper virtualMachineMapper;

    @Resource
    private VirtualClusterAddLogMapper logMapper;

    @Resource
    private RealVirtualClusterMapper realVirtualClusterMapper;

    @Resource
    private RealVirtualItemMapper virtualItemMapper;

    @Resource
    private Virtual virtual;

    @Override
    public JSONObject getDeviceMapById(JSONArray nodes, JSONArray edges, int startX, int startY, String clusterId) {
        MGlVirtualizationCluster cluster = this.getById(clusterId);
        if (cluster == null) {
            return null;
        }
        JSONObject edge, node, result;
        node = new JSONObject();
        node.put("category", MonitorConstant.VirtualCluster);
        node.put("id", cluster.getId());
        node.put("name", cluster.getName());
        node.put("ip", cluster.getIpAddress());
        node.put("x", startX + MonitorConstant.StepX);
        node.put("y", startY);
        nodes.add(node);
        result = node;

        IMGlStorageResourcesService storageResourcesService = ApplicationContextUtil.getContext().getBean(IMGlStorageResourcesService.class);
        QueryWrapper<MGlComputingResource> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(MGlComputingResource::getClusterId, cluster.getId());
        IMGlComputingResourceService computingResourceService = ApplicationContextUtil.getContext().getBean(IMGlComputingResourceService.class);
        List<MGlComputingResource> computingResourceList = computingResourceService.list(queryWrapper);
        if (computingResourceList.size() == 0) {
            return result;
        }

        IMGlNetworkResourceService mGlNetworkResourceService = ApplicationContextUtil.getContext().getBean(IMGlNetworkResourceService.class);
        MGlNetworkResource glNetworkResource;

        MGlComputingResource computingResource;
        int yComputer = startY, countNetwork = 0;
        JSONObject sChild;
        for (int i = 0; i < computingResourceList.size(); i++) {
            computingResource = computingResourceList.get(i);
            node = new JSONObject();
            node.put("category", MonitorConstant.Computer);
            node.put("id", computingResource.getId());
            node.put("name", computingResource.getName());
            node.put("ip", computingResource.getDeviceIp());
            node.put("x", startX + MonitorConstant.StepX * 2);
            node.put("y", yComputer);
            nodes.add(node);

            countNetwork = 0;


            edge = new JSONObject();
            edge.put("source", cluster.getId());
            edge.put("target", computingResource.getId());
            edges.add(edge);

            //上联光纤交换机
            if (computingResource.getUplinkOpticalSwitchId() != null && !"".equals(computingResource.getUplinkOpticalSwitchId())) {
                sChild = new JSONObject();
                sChild.put("category", MonitorConstant.Network);
                glNetworkResource = mGlNetworkResourceService.getById(computingResource.getUplinkOpticalSwitchId());
                if (glNetworkResource != null) {
                    sChild.put("id", glNetworkResource.getId());
                    sChild.put("name", computingResource.getName());
                } else {
                    sChild.put("id", computingResource.getUplinkOpticalSwitchId());
                    sChild.put("name", computingResource.getUplinkOpticalSwitch());
                }
                //node.put("ip",storageResources.getDeviceIp());
                sChild.put("x", startX + MonitorConstant.StepX * 3);
                sChild.put("y", yComputer);
                nodes.add(sChild);

                edge = new JSONObject();
                edge.put("source", computingResource.getId());
                edge.put("target", computingResource.getUplinkOpticalSwitchId());
                edges.add(edge);

                countNetwork += 1;


                //查询是否关联有存储
                MGlStorageResources storageResources = storageResourcesService.getBySwitchId(computingResource.getUplinkOpticalSwitchId());
                if (storageResources != null) {
                    sChild = new JSONObject();
                    sChild.put("category", MonitorConstant.Storage);
                    sChild.put("id", storageResources.getId());
                    sChild.put("name", storageResources.getName());
                    sChild.put("ip", storageResources.getDeviceIp());
                    sChild.put("x", startX + MonitorConstant.StepX * 4);
                    sChild.put("y", yComputer);
                    nodes.add(sChild);

                    edge = new JSONObject();
                    edge.put("source", computingResource.getId());
                    edge.put("target", computingResource.getUplinkOpticalSwitchId());
                    edges.add(edge);
                }

                yComputer += MonitorConstant.StepY;
            }
            //上联网络交换机
            if (computingResource.getOnlineNetworkSwitchId() != null && !"".equals(computingResource.getOnlineNetworkSwitchId())) {
                glNetworkResource = mGlNetworkResourceService.getById(computingResource.getOnlineNetworkSwitchId());
                String name = glNetworkResource != null ? glNetworkResource.getName() : "";
                String ip = glNetworkResource != null ? glNetworkResource.getManageIp() : "";
                sChild = new JSONObject();
                sChild.put("category", MonitorConstant.Network);
                sChild.put("id", computingResource.getOnlineNetworkSwitchId());
                sChild.put("name", name);
                sChild.put("x", startX + MonitorConstant.StepX * 3);
                sChild.put("y", yComputer);
                sChild.put("ip", ip);
                nodes.add(sChild);

                edge = new JSONObject();
                edge.put("source", computingResource.getId());
                edge.put("target", computingResource.getOnlineNetworkSwitchId());
                edges.add(edge);

                countNetwork += 1;
                yComputer += MonitorConstant.StepY;
            }

            if (computingResource.getAssociatedStorageId() != null && !"".equals(computingResource.getAssociatedStorageId())) {
                List<String> idList = Arrays.asList(computingResource.getAssociatedStorageId().split(","));
                List<MGlStorageResources> storageResourcesList = storageResourcesService.listByIds(idList);
                if (storageResourcesList.size() > 0) {
                    for (MGlStorageResources storageResources : storageResourcesList) {
                        sChild = new JSONObject();
                        sChild.put("category", MonitorConstant.Storage);
                        sChild.put("id", storageResources.getId());
                        sChild.put("name", storageResources.getName());
                        sChild.put("ip", storageResources.getDeviceIp());
                        sChild.put("x", startX + MonitorConstant.StepX * 3);
                        sChild.put("y", yComputer);

                        nodes.add(sChild);

                        edge = new JSONObject();
                        edge.put("source", computingResource.getId());
                        edge.put("target", storageResources.getId());
                        edges.add(edge);

                        yComputer += MonitorConstant.StepY;
                    }
                }
            }
        }

        return result;
    }

    @Override
    public JSONObject getDeviceTreeById(String clusterId) {
        MGlVirtualizationCluster cluster = this.getById(clusterId);
        if (cluster == null) {
            return null;
        }
        JSONObject parent, child, result, root;
        child = new JSONObject();
        child.put("type", "虚拟化群集");
        child.put("id", cluster.getId());
        child.put("name", cluster.getName());
        child.put("ip", cluster.getIpAddress());
        child.put("isCenter", 1);
        result = child;

        //List<String> idList = Arrays.asList(cluster.getComputingResourcesId().split(","));
        IMGlStorageResourcesService storageResourcesService = ApplicationContextUtil.getContext().getBean(IMGlStorageResourcesService.class);
        QueryWrapper<MGlComputingResource> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(MGlComputingResource::getClusterId, cluster.getId());
        IMGlComputingResourceService computingResourceService = ApplicationContextUtil.getContext().getBean(IMGlComputingResourceService.class);
        List<MGlComputingResource> computingResourceList = computingResourceService.list(queryWrapper);
        if (computingResourceList.size() == 0) {
            return result;
        }

        MGlComputingResource computingResource;
        JSONArray array = new JSONArray();
        JSONArray temp;
        result.put("children", array);
        for (int i = 0; i < computingResourceList.size(); i++) {
            computingResource = computingResourceList.get(i);
            child = new JSONObject();
            child.put("type", "计算资源");
            child.put("id", computingResource.getId());
            child.put("name", computingResource.getName());
            child.put("ip", computingResource.getDeviceIp());
            array.add(child);

            parent = child;
            JSONArray subNodes = new JSONArray();
            parent.put("children", subNodes);
            //上联光纤交换机
            if (computingResource.getUplinkOpticalSwitchId() != null && !"".equals(computingResource.getUplinkOpticalSwitchId())) {
                JSONObject sChild = new JSONObject();
                sChild.put("type", "交换机");
                sChild.put("id", computingResource.getUplinkOpticalSwitchId());
                sChild.put("name", computingResource.getUplinkOpticalSwitch());
                //child.put("ip",storageResources.getDeviceIp());
                subNodes.add(sChild);

                //查询是否关联有存储
                MGlStorageResources storageResources = storageResourcesService.getBySwitchId(computingResource.getUplinkOpticalSwitchId());
                if (storageResources != null) {
                    temp = new JSONArray();
                    child = new JSONObject();
                    child.put("type", "存储");
                    child.put("id", storageResources.getId());
                    child.put("name", storageResources.getName());
                    child.put("ip", storageResources.getDeviceIp());
                    temp.add(child);
                    sChild.put("children", temp);
                }
            }
            //上联网络交换机
            if (computingResource.getOnlineNetworkSwitchId() != null && !"".equals(computingResource.getOnlineNetworkSwitchId())) {
                child = new JSONObject();
                child.put("type", "交换机");
                child.put("id", computingResource.getOnlineNetworkSwitchId());
                child.put("name", computingResource.getOnlineNetworkSwitch());
                //child.put("ip",storageResources.getDeviceIp());
                subNodes.add(child);
            }

            if (computingResource.getAssociatedStorageId() != null && !"".equals(computingResource.getAssociatedStorageId())) {
                List<String> idList = Arrays.asList(computingResource.getAssociatedStorageId().split(","));
                List<MGlStorageResources> storageResourcesList = storageResourcesService.listByIds(idList);
                if (storageResourcesList.size() > 0) {
                    for (MGlStorageResources storageResources : storageResourcesList) {
                        child = new JSONObject();
                        child.put("type", "存储");
                        child.put("id", storageResources.getId());
                        child.put("name", storageResources.getName());
                        child.put("ip", storageResources.getDeviceIp());
                        subNodes.add(child);
                    }
                }
            }
        }

        return result;
    }


    @Override
    public List analysis(MGlVirtualizationCluster cluster) {
        QueryWrapper<MGlVirtualizationCluster> queryWrapper = QueryGenerator.initQueryWrapper(cluster, new HashMap<>());
        List<MGlVirtualizationCluster> clusterList = baseMapper.selectList(queryWrapper);


        List<Map<String, Object>> result = new ArrayList<>();
        BigDecimal coefficient = new BigDecimal(0);
        for (MGlVirtualizationCluster c : clusterList) {
            Map<String, Object> map = new HashMap<>();
            RealVirtualCluster real = realVirtualClusterMapper.selectByNameAndIp(c.getName(),c.getIpAddress());
            map.put("name", c.getName());
            map.put("id", c.getId());


            BigDecimal cpuCoresNo = new BigDecimal(real.getCpuHzNum()).divide(new BigDecimal(1000),2,BigDecimal.ROUND_CEILING);
            //cpu总hz数
            map.put("cpuCoresNo", cpuCoresNo);
            //内存总
            map.put("memoryModulesNo", real.getMementNum());
            //存储总
            map.put("singleHardDiskNo", real.getStorageCount());
            //总核数
            map.put("cpuKernelNum", real.getCpuKernelNum());


            BigDecimal allocationCpu = cpuCoresNo.multiply(new BigDecimal(0.75).multiply(new BigDecimal(0.8)).setScale(2, RoundingMode.HALF_UP));
            BigDecimal allocationMem = new BigDecimal(real.getMementNum()).multiply(new BigDecimal(0.75).multiply(new BigDecimal(0.8)).setScale(2, RoundingMode.HALF_UP));
            BigDecimal local = real.getStorageLocal().multiply(new BigDecimal(1024)).multiply(new BigDecimal(0.75));
            BigDecimal mount = real.getStorageMount().multiply(new BigDecimal(1024));
            BigDecimal localAddMount = local.add(mount);

            BigDecimal allocationDisk = localAddMount.multiply(new BigDecimal(0.8)).setScale(2, RoundingMode.HALF_UP);
            //可分配cpu
            map.put("allocationCpu", allocationCpu.stripTrailingZeros() );
            //可分配内存
            map.put("allocationMem", allocationMem.stripTrailingZeros());
            //可分配存储
            map.put("allocationDisk", allocationDisk.stripTrailingZeros());


            BigDecimal usedCpu = real.getCpuUsed().divide(new BigDecimal(1000),2,BigDecimal.ROUND_CEILING);
            BigDecimal residueCpu = allocationCpu.subtract(usedCpu);
            BigDecimal residueMem = allocationMem.subtract(real.getMementUsed());
            BigDecimal residueDisk = allocationDisk.subtract(real.getStorageUsed());
            //cpu剩余
            map.put("residueCpu", residueCpu.stripTrailingZeros() );
            //内存剩余
            map.put("residueMem", residueMem.stripTrailingZeros());
            //存储剩余
            map.put("residueDisk", residueDisk.stripTrailingZeros());


            //获取集群下的所有虚拟机
            List<MGlVirtualMachine> machineList = getVirtualMachineByClusterId(c.getId());
            //虚拟机总数
            map.put("machineCount", machineList.size());

            //虚机cpu核数
            map.put("machineCpuSum",this.getMachineCpuSum(machineList));


            Integer cpuNum = 0;


            map.put("cpuKernelNum",real.getCpuKernelNum());

            if (real != null) {
                //cpu主频

                BigDecimal hs = new BigDecimal(real.getCpuHzNum()).divide(new BigDecimal(1000),2,BigDecimal.ROUND_HALF_UP).divide(new BigDecimal(real.getCpuKernelNum()),2,BigDecimal.ROUND_HALF_UP);
                //系数： 集群虚拟机的配置的cpu总数*主频 / 可分配总cpu
                BigDecimal coefficientNow = this.getMachineCpuSum(machineList).multiply(hs).divide(allocationCpu,BigDecimal.ROUND_CEILING);
                coefficient = coefficient.add(coefficientNow);



                cpuNum = residueCpu.divide(new BigDecimal(8),2,BigDecimal.ROUND_HALF_UP).divide(hs,BigDecimal.ROUND_CEILING).intValue();
            }
            Integer memoryNum = residueMem.divide(new BigDecimal(16),2,BigDecimal.ROUND_HALF_UP).intValue();
//            Integer diskNum = residueDisk.divide(new BigDecimal(200),2,BigDecimal.ROUND_HALF_UP).intValue();

//            int residue = cpuNum < memoryNum ? (cpuNum < diskNum ? cpuNum : diskNum) : (memoryNum < diskNum ? memoryNum : diskNum);
            int residue = cpuNum < memoryNum ? cpuNum:memoryNum;


            map.put("residue", residue);

            result.add(map);
        }

        BigDecimal c = coefficient.divide(new BigDecimal(result.size()),2,BigDecimal.ROUND_HALF_UP);

        for (Map<String,Object> m : result) {
            //平均系数

            m.put("coefficient",c);

            int residue = new BigDecimal(m.get("residue").toString()).multiply(c).intValue();
            m.put("residue", residue);
            //echart图标数据
            List<VirtualClusterAddLog> logList = logMapper.selectByClusterId(m.get("id").toString());

            m.put("monthData", logList);
            //计算几个月资源耗尽
//            Collections.reverse(logList);
            m.put("monthNum", this.getMonthOver(logList, residue));

        }

        return result;
    }




    public List<MGlComputingResource> getComputingByClusterId(String id) {
        MGlComputingResource resource = new MGlComputingResource();
        resource.setClusterId(id);
        QueryWrapper<MGlComputingResource> wrapper = QueryGenerator.initQueryWrapper(resource, new HashMap<>());
        return computingResourceMapper.selectList(wrapper);
    }

    public List<MGlVirtualMachine> getVirtualMachineByClusterId(String id) {
        MGlVirtualMachine resource = new MGlVirtualMachine();
        resource.setClusterId(id);
        QueryWrapper<MGlVirtualMachine> wrapper = QueryGenerator.initQueryWrapper(resource, new HashMap<>());
        return virtualMachineMapper.selectList(wrapper);
    }

    public Integer getMonthOver(List<VirtualClusterAddLog> logList, int residue) {

        if (logList.size() == 0) {
            return 0;
        }

        Integer addCountNum = 0;
        for (int i = 0; i <= logList.size() - 1; i++) {
            VirtualClusterAddLog log = logList.get(i);
            //取三个月
            if (i <= 2) {
                addCountNum += log.getAddNum();
            }
        }

        if (addCountNum > 0 && residue > 0) {
            addCountNum = addCountNum / 3;
            return new BigDecimal(residue).divide(new BigDecimal(addCountNum),2,BigDecimal.ROUND_HALF_UP).setScale(0, RoundingMode.UP).intValue();
        }

        return 0;
    }


    public void getHomeData(List<MGlVirtualizationCluster> clusterList) {

        for (MGlVirtualizationCluster c : clusterList) {

            RealVirtualCluster cluster = realVirtualClusterMapper.selectByNameAndIp(c.getName(),c.getIpAddress());

            if (cluster!=null){

                c.setCpuKernelNum(cluster.getCpuKernelNum());
                c.setUsedCpu(cluster.getCpuUsed().divide(new BigDecimal(1000),2,BigDecimal.ROUND_CEILING));
                c.setCpuCapacity(new BigDecimal(cluster.getCpuHzNum()).divide(new BigDecimal(1000),2,BigDecimal.ROUND_CEILING));
                c.setUsedMemory(cluster.getMementUsed());
                c.setMemoryCapacity(cluster.getMementNum().toString());
                c.setUsedStorage(cluster.getStorageUsed());
                c.setStorageCapacity(cluster.getStorageCount().toString());

            }

        }
    }


    public BigDecimal getMachineCpuSum(List<MGlVirtualMachine> machineList){
        BigDecimal res = new BigDecimal(0);
        for (MGlVirtualMachine machine : machineList){
            if (CommonUtils.isBigDecimal(machine.getVcpuNo())){
                res  = res.add(new BigDecimal(machine.getVcpuNo()));
            }
        }
        return res;
    }

    public void setMonData(Map<String,Object> map,List<MGlVirtualizationCluster> clusterList) {

        List<MGlVirtualMachine> machineList = virtualMachineMapper.selectAll();

        List<RealVirtualItem> items = virtualItemMapper.selectAll();

        for (MGlVirtualizationCluster cluster : clusterList){
            cluster.setMonitorStatus(map.get(cluster.getIpAddress()).toString());

            RealVirtualCluster cluster1  = virtual.getRealVirtualClusterByIpAndName(cluster.getIpAddress(),cluster.getName());
            if (cluster1!=null){
                cluster.setHostNum(cluster1.getHostNum());

                cluster.setMachineNum(this.getMachineNumById(cluster.getId(),machineList));
                cluster.setOpenNum(this.getOpenNum(cluster1.getId(),items));

            }
        }
    }

    public int getMachineNumById(String id,List<MGlVirtualMachine> machineList){
        int r = 0;
        for (MGlVirtualMachine machine : machineList){
            if (machine.getClusterId().equals(id)){
                r ++;
            }
        }

        return r;
    }

    public int getOpenNum(String id,List<RealVirtualItem> items){
        int r = 0;
        for (RealVirtualItem item : items){
            if ("1".equals(item.getStatus()) && id.equals(item.getClusterId())){
                r ++;
            }
        }
        return r;
    }

    public String getIp(String id){
        return baseMapper.selectById(id).getIpAddress();
    }



}
